package com.happymmall.Filter;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;

import javax.crypto.SecretKey;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@WebFilter(urlPatterns = "/*")
public class Filter implements javax.servlet.Filter {
    // JWT签名密钥
    private static final String JWT_SECRET = "this-is-a-test-secret-key-with-32-or-more-chars";

    // 无需Token即可访问的接口
    private static final Map<String, Boolean> WHITE_LIST = new HashMap<String, Boolean>() {{
        put("/user/login.do", true);
        put("/user/register.do", true);
        put("/user/forget_get_question.do", true);
        put("/user/forget_check_answer.do", true);
        put("/user/forget_reset_password.do", true);
        put("/user/check_valid.do", true);
        put("/user/logout.do", true);


    }};

//    // 场景映射：路径前缀 -> 所需Token类型（用于多场景校验）
//    private static final Map<String, String> SCENE_MAPPING = new HashMap<String, String>() {{
//        put("/api/user/", "user_auth");       // 用户中心接口需用户认证Token
//        put("/api/order/", "order_auth");     // 订单接口需订单权限Token
//        put("/api/reset/", "reset_auth");     // 密码重置接口需重置专用Token
//        put("/api/pay/", "payment_auth");     // 支付接口需支付授权Token
//    }};

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 过滤器初始化方法：可用于加载配置文件等初始化操作
        System.out.println("TokenFilter初始化完成");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        // 转换为HTTP请求响应对象
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setContentType("application/json;charset=utf-8");

        // 1. 计算真实路径（去除上下文）
        String requestURI = httpRequest.getRequestURI();
        String contextPath = httpRequest.getContextPath();
        String realPath = contextPath.isEmpty() ? requestURI : requestURI.substring(contextPath.length());

        // 2. 白名单校验：匹配成功则立即放行，且不再执行后续逻辑
        if (WHITE_LIST.containsKey(realPath)) {
            System.out.println("路径在白名单中，直接放行: " + realPath); // 新增日志，确认执行到这里
            chain.doFilter(request, response);
            return; // 关键：必须return，终止当前方法，避免进入Token验证
        }

        // 3. 提取Token：从Authorization请求头获取
        String token = httpRequest.getHeader("Authorization");
        if (token == null || token.trim().isEmpty()) {
            sendErrorResponse(httpResponse, 401, "未携带Token，请先获取有效Token");
            return;
        }

        // 4. 解析Token并校验基本有效性
        Claims claims;
        try {
            // 解析Token并验证签名
            SecretKey key = Keys.hmacShaKeyFor(JWT_SECRET.getBytes(StandardCharsets.UTF_8));
            claims = Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
        } catch (
                ExpiredJwtException e) {
            sendErrorResponse(httpResponse, 401, "Token已过期，请重新获取");
            return;
        } catch (
                SignatureException e) {
            sendErrorResponse(httpResponse, 401, "Token签名无效，可能被篡改");
            return;
        } catch (Exception e) {
            sendErrorResponse(httpResponse, 401, "Token无效，格式错误或已失效");
            return;
        }

//        // 4. 多场景Token类型校验
//        String requiredTokenType = getRequiredTokenType(requestPath);
//        if (requiredTokenType == null) {
//            sendErrorResponse(httpResponse, 403, "未配置该接口的访问权限规则");
//            return;
//        }
//
//        // 获取Token中实际的类型标识
//        String actualTokenType = claims.get("type", String.class);
//        if (!requiredTokenType.equals(actualTokenType)) {
//            sendErrorResponse(httpResponse, 401, "Token类型不匹配，需要" + requiredTokenType + "类型的Token");
//            return;
//        }

        // 5. 提取Claims中的关键信息，存入request供后续接口使用
        httpRequest.setAttribute("userId", claims.get("userId", Integer.class));
        httpRequest.setAttribute("username", claims.get("username", String.class));
        httpRequest.setAttribute("fullClaims", claims); // 存储完整的Claims对象

        // 6. 校验通过，放行到后续处理器（Servlet/Controller）
        chain.doFilter(request, response);
    }


    @Override
    public void destroy() {
        // 过滤器销毁方法：可用于释放资源
        System.out.println("TokenFilter已销毁");
    }


//        /**
//         * 判断当前请求路径是否在白名单中
//         * @param requestPath 请求路径
//         * @return 是否为白名单路径
//         */
//        private boolean isWhiteListPath(String requestPath) {
//            // 精确匹配白名单路径
//            if (WHITE_LIST.containsKey(requestPath)) {
//                return true;
//            }
//            // 通配符匹配（如/static/开头的路径）
//            for (String whitePath : WHITE_LIST.keySet()) {
//                if (whitePath.endsWith("/") && requestPath.startsWith(whitePath)) {
//                    return true;
//                }
//            }
//            return false;
//
//        }

    /**
     * 根据请求路径获取所需的Token类型
     * @param requestPath 请求路径
     * @return 所需Token类型，未匹配到返回null
     */
    //    private String getRequiredTokenType(String requestPath) {
    //        for (Map.Entry<String, String> entry : SCENE_MAPPING.entrySet()) {
    //            if (requestPath.startsWith(entry.getKey())) {
    //                return entry.getValue();
    //            }
    //        }
    //        return null;
    //    }

    /**
     * 发送标准化的错误响应
     *
     * @param response 响应对象
     * @param code     状态码
     * @param message  错误信息
     */
    private void sendErrorResponse(HttpServletResponse response, int code, String message) throws IOException {
        PrintWriter out = response.getWriter();
        out.write("{\"code\":" + code + ",\"msg\":\"" + message + "\"}");
        out.flush();
        out.close();
    }

}





